package com.kzn.util.tmp;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;


/**
 * DHash 算法对图片去重
 * @author sorclown
 * @date 2022/2/7
 */
public class DHashUtil {
    /**
     * 计算dHash方法
     *
     * @param file 文件
     * @return hash
     */
    private static long getDHash(File file) {
        //读取文件
        BufferedImage srcImage;
        try {
            srcImage = ImageIO.read(file);
        } catch (IOException e) {
            e.printStackTrace();
            return -1;
        }

        //文件转成9*8像素，为算法比较通用的长宽
        BufferedImage buffImg = new BufferedImage(9, 8, BufferedImage.TYPE_INT_RGB);
        buffImg.getGraphics().drawImage(
                srcImage.getScaledInstance(9, 8, Image.SCALE_SMOOTH), 0,
                0, null);

        //图片灰度化，灰度和加亮算法是网上找的，本人不懂图像
        int width = buffImg.getWidth();
        int height = buffImg.getHeight();
        int[] grayPix = new int[width * height];
        int i = 0;
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int rgb = buffImg.getRGB(x, y);
                int r = rgb >> 16 & 0xff;
                int g = rgb >> 8 & 0xff;
                int b = rgb & 0xff;
                int gray = (r * 30 + g * 59 + b * 11) / 100;
                grayPix[i++] = gray;
            }
        }

        //开始计算dHash 总共有9*8像素 每行相对有8个差异值 总共有 8*8=64 个
        long figure = 0;
        for (i = 0; i < 63; i++) {
            long bit = grayPix[i] > grayPix[i + 1] ? 1 : 0;
            figure |= bit << i;
        }
        return figure;
    }

    /**
     * 计算海明距离, 计网接触过的
     * <p>
     * 原本用于编码的检错和纠错的一个算法
     * 现在拿来计算相似度，如果差异值小于一定阈值则相似
     *
     * @param x hash
     * @param y hash
     * @return 距离
     */
    private static long getHammingDistance(long x, long y) {
        int cnt = 0;
        x = x ^ y;
        while (x != 0) {
            if (1 == (x & 0x01)) {
                cnt++;
            }
            x = x >> 1;
        }
        return cnt;
    }

    /**
     * 去重函数
     *
     * @param files 文件列表
     */
    public static void doDistinct(File[] files) {
        //以File作Key, hash作val 新建一个map
        Map<File, Long> hashMap = new HashMap<>();

        for (File file : files){
            hashMap.put(file.getAbsoluteFile(),DHashUtil.getDHash(file));
        }

        //有效的hashList
        List<Long> hashList = new ArrayList<>();



        //去重循环
        for (Iterator<Map.Entry<File, Long>> it = hashMap.entrySet().iterator(); it.hasNext(); ) {
            Map.Entry<File, Long> entry = it.next();
            //如果判定为重复，则移除map且删除
            if (entry.getValue() != -1 && hashList.parallelStream().anyMatch(hash -> getHammingDistance(entry.getValue(), hash) < 10)) {
                it.remove();
                entry.getKey().deleteOnExit();
                return;
            }
            //不重复/第一次 直接加入hashList
            hashList.add(entry.getValue());
        }
    }

    //DHashUtil 参数值为待处理文件夹
    public static void main(String[] args) {
        File file = new File(args[0]);
        if (file.isDirectory()) {
            doDistinct(file.listFiles());
        }
    }
}
